/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
//
//  filename: 	LaborMathTemplate.h
//  created:	10:03 8/6/2006
//  author:		rock.mao  2006.
//	Description:
//		
//
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __LABOR_MATHTEMPLATE_H__
#define __LABOR_MATHTEMPLATE_H__
#include "../LaborCoreDef.h"
NAMESPACE_LABOR3D_BEGIN

/*!
\brief
The System class is the CXGUI class that provides access to all other elements in this system.

This object must be created by the client application.  The System object requires that you pass it
an initialised Renderer object which it can use to interface to whatever rendering system will be
used to display the GUI imagery.
*/
template <typename T>
class CLPoint2DT
{
	typedef CLPoint2DT<T> point_type;
public:
	typedef T value_type;

	/*!
	\brief
	Constructor for a 2D point.
	*/

	CLPoint2DT(void) {}
	CLPoint2DT(T _x, T _y):x(_x), y(_y){}

	void zero()
	{
		x = 0;
		y = 0;
	}
	/*!
	\brief
	Destructor for a 2D point.
	*/
	~CLPoint2DT(void){}


	void set( T _x, T _y ){
		x = _x;
		y = _y;
	}

	void normalize( float _fVal ){
		float t_factor = _fVal / (float)sqrt(x*x + y*y );
		x *= t_factor;
		y *= t_factor;
	}

	/*************************************************************************
	Operators
	*************************************************************************/
	point_type& operator*=
		(const point_type& _point) {
			x *= _point.x;
			y *= _point.y;

			return *this;
	}

	point_type& operator/=
		(const point_type& _point) {
			x /= _point.x;
			y /= _point.y;

			return *this;
	}

	point_type& operator+=
		(const point_type& _point) {
			x += _point.x;
			y += _point.y;

			return *this;
	}

	point_type& operator-=
		(const point_type& _point) {
			x -= _point.x;
			y -= _point.y;

			return *this;
	}

	point_type operator+
		(const point_type& _point)const {
			return point_type(x+_point.x, y + _point.y);
	}

	point_type operator-
		(const point_type& _point)const {
			return point_type(x-_point.x, y-_point.y);
	}

	point_type operator*
		(const point_type& _point)const {
			return point_type(x*_point.x, y*_point.y);
	}

	point_type operator*( float _fValue ) const{
		return point_type( _fValue*x, _fValue*y );
	}

	bool operator==
		(const point_type& _point)const {
			return ((x==_point.x)&&(y==_point.y));
	}

	bool operator!=
		(const point_type& _point)const {
			return (!operator==(_point));
	}

	/*************************************************************************
	Data Fields
	*************************************************************************/

	T x, y;
};


/*!
\brief
template CLSizeT description the size of rectangle,
that include width and height.
*/

template <typename T>
class CLSizeT
{
public:
	typedef T value_type;

	/*!
	\brief
	Constructor for a Size.
	*/
	CLSizeT(void)	{ }
	CLSizeT(T _width, T _height):d_Width(_width), 
		d_Height(_height){}

	/*************************************************************************
	Data Fields
	*************************************************************************/

	T d_Width, d_Height;
};



/*!
\brief
template class CLRectT description a rectangle,
that include the d_Top,d_Bottom,d_Left,d_Right of the
rectangle.
*/

template <typename T>
class CLRectT
{
	typedef CLPoint2DT<T> point_type;
	typedef CLSizeT<T>	 size_type;
	typedef CLRectT<T>	 rect_type;

public:
	typedef T value_type;
	/*!
	\brief
	Constructor for a rect.
	*/

	CLRectT(void) { }

	CLRectT(T& _t) : d_Top(_t), d_Bottom(_t), d_Left(_t), d_Right(_t){
	}
	CLRectT(T _Left, T _Top, T _Right, T _Bottom)
		:d_Left(_Left), d_Top(_Top), d_Right(_Right), 
		d_Bottom(_Bottom) { }

	/*!
	\brief
	Destructor for a rect.
	*/
	~CLRectT(void) {}

	/*!
	\brief
	return width of rect area

	*/

	T getWidth(void)const { return d_Right-d_Left;}

	/*!
	\brief
	return height of rect area

	*/
	T getHeight(void)const { return d_Bottom - d_Top;}

	/*!
	\brief
	return left top corner coordinate of the rect area

	*/

	point_type getLeftTopPos(void) const	{
		return point_type(d_Left, d_Top);
	}

	/*!
	\brief
	return left bottom corner coordinate of the rect area

	*/
	point_type getLeftBottomPos(void) const	{
		return point_type(d_Left, d_Bottom);
	}

	/*!
	\brief
	return right bottom corner coordinate of the rect area

	*/
	point_type getRightBottomPos(void) const	{
		return point_type(d_Right, d_Bottom);
	}

	/*!
	\brief
	return right top corner coordinate of the rect area

	*/
	point_type getRightTopPos(void) const	{
		return point_type(d_Right, d_Top);
	}

	/*!
	\brief
	return the center point of rect area

	*/
	point_type getCenterPt(void) const {
		return point_type( d_Left + getWidth()/T(2), 
			d_Bottom + getHeight()/T(2));
	}

	/*!
	\brief
	return the size of the rect area

	*/
	size_type getSize(void)const {
		return size_type(getWidth(), getHeight());
	}

	/*!
	\brief
	set the width of the rect object
	*/
	void setWidth(T _width)	{ d_Right = d_Left + _width; }

	/*!
	\brief
	set the height of the rect object
	*/
	void setHeight(T _height)	{ d_Bottom = d_Top + _height; }

	/*!
	\brief
	set the size of the rect area
	*/
	void setSize(const size_type& _size) {
		setWidth(_size.d_Width);
		setHeight(_size.d_Height);
	}

	/*!
	\brief
	set the position of the rect (leaves size in tact)
	*/

	void setPos(const point_type& _pt)		{
		size_type t_sz(getSize());

		d_Left    = _pt.x;
		d_Bottom  = _pt.y;
		setSize(t_sz);
	}

	/*!
	\brief
	Moves rect to the specified x-coordinates
	*/
	void moveToX(const T _x)	{
		size_type t_size(getSize());

		d_Left = _x;
		setSize(t_size);
	}

	/*!
	\brief
	Moves rect to the specified y-coordinates
	*/
	void moveToY(const T _y)	{
		size_type t_size(getSize());

		d_Bottom = _y;
		setSize(t_size);
	}

	/*!
	\brief
	Moves rect to the x and y-coordinates
	*/
	void moveToXY(const point_type& _point) {
		size_type t_size(getSize());

		d_Left   = _point.x;
		d_Bottom = _point.y;
		setSize(t_size);
	}

	/*!
	\brief
	return a rect that is the intersection of 'this' rect with the rect '_rect'

	\note
	It can be assumed that if d_left == d_right, or d_top == d_bottom, or getWidth() == 0, or getHeight() == 0, then
	'this' rect was totally outside '_rect'.
	*/
	rect_type getIntersection
		(const rect_type& _rect)const	
	{
		if ((d_Right>_rect.d_Left) &&
			(d_Left<_rect.d_Right) &&
			(d_Top<_rect.d_Bottom) &&
			(d_Bottom>_rect.d_Top)) 
		{
			return rect_type(
				(d_Left>_rect.d_Left) ? d_Left:_rect.d_Left,
				(d_Top>_rect.d_Top) ? d_Top:_rect.d_Top,
				(d_Right<_rect.d_Right) ? d_Right:_rect.d_Right,
				(d_Bottom<_rect.d_Bottom) ? d_Bottom:_rect.d_Bottom);
		}

		return rect_type(0, 0, 0, 0);
	}

	rect_type& constrainSize(const size_type& Max, 
		const size_type& Min)	
	{
		size_type curr(getSize());

		if (curr.Width > Max.Width)
		{
			setWidth(Max.Width);
		}
		else if (curr.Width < Min.Width)
		{
			setWidth(Min.Width);
		}

		if (curr.Height > Max.Height)
		{
			setHeight(Max.Height);
		}
		else if (curr.Height < Min.Height)
		{
			setHeight(Min.Height);
		}

		return *this;
	}

	/*!
	\brief
	Applies an _offset the rect object

	\param _delta
	Point object containing the offsets to be applied to the rect.

	\return
	this rect after the _offset is performed
	*/

	rect_type& _offset(const point_type& _delta) {
		d_Left   += _delta.x;
		d_Right  += _delta.x;
		d_Top	 += _delta.y;
		d_Bottom += _delta.y;

		return *this;
	}

	/*!
	\brief
	Return true if the given Point falls within this rect

	\param _pt
	Point object describing the position to test.

	\return
	true if position  _pt is within this Rect's area, else false
	*/

	bool isPtInRect(const point_type& _pt) const	{
		if ((d_Left <= _pt.x) && (d_Right  > _pt.x) &&
			(d_Top  <= _pt.y) && (d_Bottom > _pt.y))
		{
			return true;
		}

		return false;
	}

	/*************************************************************************
	Operators
	*************************************************************************/
	bool operator== (const rect_type& r) const {
		return ((d_Top == r.d_Top) && (d_Bottom == r.d_Bottom) 
			&& (d_Left == r.d_Left) && (d_Right == r.d_Right));
	}

	bool operator!= (const rect_type& r) const {
		return !operator==(r);
	}

	/*************************************************************************
	Data Fields
	*************************************************************************/
	T d_Top, d_Bottom, d_Left, d_Right;

};

typedef CLPoint2DT<int>   CLPoint2D;
typedef CLPoint2DT<float> CLPoint2DF;

typedef CLSizeT<int>   CLSize;
typedef CLSizeT<float> CLSizeF;

typedef CLRectT<int>   CLRect;
typedef CLRectT<float> CLRectF;

NAMESPACE_LABOR3D_END


#endif//__LABOR_MATHTEMPLATE_H__
